/**
 * 开发者   : Marco
 * 创建时间 : 2017年4月6日, 下午4:23
 */

#if (defined(__cplusplus) && __cplusplus >= 201103L)

#include "pool.h"

#if defined(MYSQLPP_MYSQL_HEADERS_BURIED)
#include <mysql++/options.h>
#else
#       include <options.h>
#endif

namespace marco {
namespace mysql {

poolbase::poolbase(const char* db, const char* server, const char* user, const char* pwd, 
	unsigned short port, int size, bool exception) : size_(size), port_(port), exception_(exception) {
    if (db) db_ = db;
    if (server) server_ = server;
    if (user) user_ = user;
    if (pwd) pwd_ = pwd;
    
    if (size) {
	for (int i = 0; i < size; ++i) {
	    pool_.emplace_back(create());
	}
    }
}

bool poolbase::reconnect(connection_ptr conn) {
    return conn->connect(
	    db_.empty() ? 0 : db_.c_str(),
	    server_.empty() ? 0 : server_.c_str(),
	    user_.empty() ? 0 : user_.c_str(),
	    pwd_.empty() ? 0 : pwd_.c_str(),
	    (unsigned int)port_
    );
}

void poolbase::clear(void) {
    for (auto& conn : pool_)
	destroy(conn);
    
    pool_.clear();
    size_ = 0;
}

connection_ptr poolbase::create(void) {
    auto conn = new mysqlpp::Connection(exception_);
    
    conn->set_option(new mysqlpp::ReconnectOption(true)); // 设置自动连接
    conn->set_option(new mysqlpp::SetCharsetNameOption("utf8")); // 字符集
    conn->set_option(new mysqlpp::ConnectTimeoutOption(5)); // 连接超时
    
    conn->connect(
	    db_.empty() ? 0 : db_.c_str(), 
	    server_.empty() ? 0 : server_.c_str(),
	    user_.empty() ? 0 : user_.c_str(), 
	    pwd_.empty() ? 0 : pwd_.c_str(), 
	    (unsigned int)port_
    );
    
    return conn;
}


// ------------- mysqlpool

connection_ptr pool::grab(void) {
    {
	iterator it;
	std::unique_lock<std::mutex> lck(mtx_);
	if (!empty()) {
	    size_ -= 1;
	    it = pool_.begin(); // 从列表移除, 拿到迭代器
	    pool_.erase(it);
	    return *it;
	}
    }
    return create();
}

void pool::release(const connection_ptr pc) {
    std::unique_lock<std::mutex> lck(mtx_);
    poolbase::release(pc);
}


// ----------- mysqlwaitpool

connection_ptr waitpool::grab(void) {
    iterator it;
    std::unique_lock<std::mutex> lck(mtx_);
   
    while (empty()) 
	cv_.wait(lck);
    
    it = pool_.begin(); // 从列表移除, 拿到迭代器
    pool_.erase(it);
    size_ -= 1;
    
    return *it;
}

void waitpool::release(const connection_ptr pc) {
    std::unique_lock<std::mutex> lck(mtx_);
    poolbase::release(pc);
    cv_.notify_one();
}

} // end namespace mysql
} // end namespace marco

#endif // defined(__cplusplus) && __cplusplus >= 201103L



